/**
 * 
 */
package fr.gfi.agraf.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import fr.gfi.agraf.exception.AgrafException;
import fr.gfi.agraf.persistence.dao.IActiviteDAO;
import fr.gfi.agraf.persistence.dao.IEtatDAO;
import fr.gfi.agraf.persistence.dao.IPerimetreDAO;
import fr.gfi.agraf.persistence.dao.ITacheDAO;
import fr.gfi.agraf.persistence.dao.IUtilisateurDAO;
import fr.gfi.agraf.persistence.entity.Activite;
import fr.gfi.agraf.persistence.entity.Etat;
import fr.gfi.agraf.persistence.entity.Perimetre;
import fr.gfi.agraf.persistence.entity.Tache;
import fr.gfi.agraf.persistence.entity.Utilisateur;
import fr.gfi.agraf.service.IImportService;
import fr.gfi.agraf.service.INotificationService;
import fr.gfi.agraf.service.mapper.UtilisateurMapper;
import fr.gfi.agraf.utils.PropertiesUtils;
import fr.gfi.agraf.vue.bean.LigneExcelImportBean;

/**
 * @author Fw
 * 
 */
@Service("ImportService")
@Transactional(propagation = Propagation.REQUIRED)
public class ImportService implements IImportService {

	private static final String FORMAT_INVALIDE = "formatInvalideExcel";
	private static final String ERREUR_TECHNIQUE = "erreurTechnique";
	private static final Long ID_PROFIL_ADMINISTRATEUR = 1L;
	private static final String NOTIF_IMPORT = "notification.import.tache";

	@Autowired
	private IEtatDAO etatDAO;

	@Autowired
	private IActiviteDAO activiteDAO;

	@Autowired
	private ITacheDAO tacheDAO;

	@Autowired
	private IPerimetreDAO perimetreDAO;

	@Autowired
	private IUtilisateurDAO utilisateurDAO;

	@Autowired
	private INotificationService notificationService;

	public List<LigneExcelImportBean> traiterImport(final File fileUploaded, final Long idPerimetre,
			final Long idUtilisateurCreateur) throws AgrafException {

		// J'ouvre le fichier...
		Workbook fichierExcel = null;
		try {
			fichierExcel = WorkbookFactory.create(fileUploaded);
		} catch (final InvalidFormatException e) {
			throw new AgrafException(FORMAT_INVALIDE);
		} catch (final IOException e) {
			throw new AgrafException(ERREUR_TECHNIQUE);
		}

		// J'ouvre la feuille
		// Je recherche d'abord par nom
		Sheet feuilleExcel = fichierExcel.getSheet("Détail des charges");
		// Sinon je prend la premiere position
		if (feuilleExcel == null) {
			feuilleExcel = fichierExcel.getSheetAt(0);
		}

		final List<LigneExcelImportBean> listeActiviteRecuperee = new ArrayList<LigneExcelImportBean>();
		// Je commence l'itération ligne 7, car l'entete ne nous interesse pas
		int index = 7;
		// Puis je lance la lecture
		Row row = feuilleExcel.getRow(index);

		while (row != null) {
			listeActiviteRecuperee.add(getBeanFromRow(row, index));
			row = feuilleExcel.getRow(++index);
		}

		final Perimetre perimetre = perimetreDAO.read(idPerimetre);
		final List<LigneExcelImportBean> listeOutput = traiterListeBean(listeActiviteRecuperee, perimetre);

		// S'il y a eu des données, alors je notifie les administrateur de cet
		// ajout
		final Utilisateur userCreateur = utilisateurDAO.read(idUtilisateurCreateur);
		if (listeOutput != null && listeOutput.size() != 0) {
			notificationService.envoyerNotificationToUtilisateurByProfil(PropertiesUtils.getProperty(
					NOTIF_IMPORT, UtilisateurMapper.getConcatenationPrenomNom(userCreateur),
					perimetre.getLibelle()), ID_PROFIL_ADMINISTRATEUR);
		}

		return listeOutput;

	}

	/**
	 * Traite la liste des beans récuperé depuis l'import excel
	 * 
	 * @param listeBeans
	 */
	private List<LigneExcelImportBean> traiterListeBean(final List<LigneExcelImportBean> listeBeans,
			final Perimetre perimetre) {
		Activite activiteTemp = null;
		final Etat etatCree = etatDAO.read(1L);
		final List<LigneExcelImportBean> lignesAjoutees = new ArrayList<LigneExcelImportBean>();

		for (final LigneExcelImportBean bean : listeBeans) {
			// Je ne traite que les lignes valides
			if (bean.isLigneValide()) {
				if (bean.isLigneActivite()) {
					activiteTemp = new Activite();
					activiteTemp.setDateCreation(new Date());
					activiteTemp.setEtat(etatCree);
					activiteTemp.setLibelle(bean.getLibelleActivite());
					activiteTemp.setRemarque(bean.getRemarqueActivite());
					activiteTemp.setPerimetre(perimetre);
					activiteDAO.persist(activiteTemp);
					lignesAjoutees.add(bean);
				} else {
					if (activiteTemp == null) {
						// Ceci ne devrait jamais arrivé
						continue;
					}
					final Tache tache = new Tache();
					tache.setChargeInit(bean.getChargeTache());
					tache.setCommentaire(bean.getRemarqueTache());
					tache.setDateCreation(new Date());
					tache.setEtat(etatCree);
					tache.setLibelle(bean.getLibelleTache());
					tache.setActivite(activiteTemp);
					tacheDAO.persist(tache);
					lignesAjoutees.add(bean);
				}
			}
		}
		return lignesAjoutees;
	}

	/**
	 * Traite une ligne de lecture du fichier excel
	 * 
	 * @param row
	 * @return
	 */
	private LigneExcelImportBean getBeanFromRow(final Row row, final int index) {
		final LigneExcelImportBean ligneRecup = new LigneExcelImportBean();

		ligneRecup.setIndexLigne(index);
		isLigneActivite(ligneRecup, row);
		isLigneTache(ligneRecup, row);

		return ligneRecup;
	}

	/**
	 * Vérifie si la ligne concernen une tache, et remplie le bean le cas
	 * échéant
	 * 
	 * @param ligneRecup
	 * @param row
	 * @return
	 */
	private void isLigneTache(final LigneExcelImportBean ligneRecup, final Row row) {

		// Dans le cas de la deniere ligne, il faut passer
		if (row.getCell(2) == null) {
			return;
		}
		final String libelleEventuelTache = row.getCell(2).getStringCellValue();
		if (!libelleEventuelTache.isEmpty()) {
			if (row.getCell(5) != null && row.getCell(7) != null) {

				Double chargeEnventuelleTache;
				String remarqueEventuelleTache;
				try {
					chargeEnventuelleTache = row.getCell(5).getNumericCellValue();
					remarqueEventuelleTache = row.getCell(7).getStringCellValue();
				} catch (final IllegalStateException e) {
					// La ligne est incorrect, je return sans actions
					return;
				}

				ligneRecup.setLibelleTache(libelleEventuelTache);
				ligneRecup.setChargeTache(chargeEnventuelleTache);
				ligneRecup.setRemarqueTache(remarqueEventuelleTache);
				ligneRecup.setLigneValide(true);
				ligneRecup.setLigneTache(true);
			}
		}
	}

	/**
	 * Vérifie si la ligne concerne une activite, et remplie le bean le cas
	 * échéant
	 * 
	 * @param ligneRecup
	 * @param row
	 * @return
	 */
	private void isLigneActivite(final LigneExcelImportBean ligneRecup, final Row row) {

		if (row.getCell(2) == null) {
			return;
		}
		if (row.getCell(1) == null) {
			return;
		}
		final String libelleEventuelActivite = row.getCell(1).getStringCellValue();
		if (libelleEventuelActivite.isEmpty()) {
			ligneRecup.setLigneActivite(false);
		} else {
			// Pour être une activité, des données doivent exister dans la cell
			// n°7
			if (row.getCell(5) == null || row.getCell(6) == null) {
				// Dans le cas ou les cellules sont fusionnées, la ligne n'est
				// pas valide
				ligneRecup.setLigneActivite(false);
			} else {
				String remarqueEventuelleActivite;
				try {
					remarqueEventuelleActivite = row.getCell(7).getStringCellValue();
				} catch (final IllegalStateException e) {
					// La ligne est corrompue, je return sans action
					ligneRecup.setLigneActivite(false);
					return;
				}
				
				// Je fait un test sur la case 6, si elle n'a aucune valeur, alors il sagit d'un séparateur qu'il ne faut pas traiter
				String contenantCell5 = "";
				try {
					contenantCell5 = row.getCell(5).getStringCellValue();
				} catch (final IllegalStateException e) {
					ligneRecup.setLigneActivite(false);
					return;
				}
				
				if (contenantCell5.equals("")){
					ligneRecup.setLigneActivite(false);
					return;
				}

				ligneRecup.setLigneActivite(true);
				ligneRecup.setLigneValide(true);
				ligneRecup.setLibelleActivite(libelleEventuelActivite);
				ligneRecup.setRemarqueActivite(remarqueEventuelleActivite);
			}
		}
	}

}
